package util

import (
	"fmt"
	"io/ioutil"
	"log"
	"mp4/entity"
	"net/http"
	"os"
	"os/exec"
	"strings"
)

func DownloadM3u8Http(m3u8 string, config entity.DownloadEntity, responseEntity entity.ResponseEntity, title string) (bool, []string) {
	filePath := config.FileDirPath + "/" + title + config.AudioType
	//start := time.Now()
	var paths []string
	if ExistsFile(filePath, config) {

		paths = append(paths, filePath)
		return true, paths
	}

	resp, _ := createResponse(m3u8, responseEntity)
	defer func() {
		if nil != resp && nil != resp.Body {
			resp.Body.Close()
			resp.Body = nil
		}
		resp = nil
	}()

	if nil == resp {

		log.Println(m3u8, "---> response is null")
		return true, paths
	}

	if resp.StatusCode != 200 && resp.StatusCode != 206 {
		log.Println(m3u8, "--->", resp.StatusCode)
	}

	b, error := ioutil.ReadAll(resp.Body)
	if nil != error {
		log.Println(m3u8, "---read---", error)
		return true, nil
	}
	urls := chooseHURL(string(b), config)
	flag, tsPath, length := downloadContent(urls, config, responseEntity, title)
	var filePath1 string
	var path string
	var zipPath string
	if length <= len(urls)-2 {
		return false, paths
	}

	flag, filePath1 = writeFile(urls, config, title)

	if flag {
		flag, path = SysnthesisTsToMp4(path, config, filePath1)
		if flag {
			flag, paths = ValidateFile(path, config, paths)
		}

		if !flag {
			os.Remove(filePath1)
			flag, zipPath = ZipOf7Z(title, tsPath, config)
			if flag {
				flag, path = ConvertToMpt(zipPath, filePath, config)
				if flag {
					os.Remove(zipPath)
				}
			}

			if flag {
				flag, paths = ValidateFile(path, config, paths)
			}
		}
	}

	if flag {
		//sleepAndPrint(SLEEP_VALUE, start)
	}

	paths = append(paths, path)
	return !flag, paths
}

func downloadContent(urls []entity.URLEntity, config entity.DownloadEntity, responseEntity entity.ResponseEntity, title string) (bool, string, int) {
	if len(urls) > 0 {
		path := config.FileDirPath + "/" + title + "_ts"
		if ExistsDir(path) {
			os.MkdirAll(path, os.ModePerm)
		}

		flag := true
		var er error
		index := 0
		for _, entity := range urls {
			fileName := path + "/" + entity.Title + config.AudioChildType
			if ExistsFile(fileName, config) {
				flag, er = downFileContent(entity, responseEntity, fileName)
				if nil != er {
					log.Println("create or write File error :", entity.URL, "-->", er)
					flag = false
				}
				if !flag {
					flag = false
				} else {
					index++
				}
			} else {
				index++
			}

		}
		return flag, path, index
	}
	return false, "", 0
}

func writeFile(urls []entity.URLEntity, config entity.DownloadEntity, title string) (bool, string) {
	if len(urls) > 0 {
		path := config.FileDirPath + "/" + title + "_ts"
		if ExistsDir(path) {
			os.MkdirAll(path, os.ModePerm)
		}
		filePath := path + "/file.txt"
		if ExistsFile(filePath, config) {
			os.Remove(filePath)
		}
		openFile, e := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, 777)
		defer func() {
			if nil != openFile {
				openFile.Close()
				openFile = nil
			}
		}()
		if e != nil {
			log.Println(e)
		}
		for _, entity := range urls {
			openFile.WriteString("file '" + entity.Title + "'\n")
		}
		return true, filePath
	}
	return false, ""
}

func downFileContent(entity entity.URLEntity, responseEntity entity.ResponseEntity, path string) (bool, error) {
	resp, _ := createResponse(entity.URL, responseEntity)
	var ero error
	defer func() {
		if nil != resp && nil != resp.Body {
			ero = resp.Body.Close()
			resp.Body = nil
		}

		resp = nil
	}()
	return WriteFile(path, entity.URL, resp), ero

}

func chooseHURL(content string, configEntity entity.DownloadEntity) []entity.URLEntity {
	if IsEmpty(content) {
		return nil
	}
	if strings.Index(content, ".m3u8") > 0 {
		return nil
	}
	urlStrs := strings.Split(content, "\n")
	var urls []entity.URLEntity
	//var httpURLs []string
	//var httpsURLs []string

	for index, url := range urlStrs {
		if strings.HasPrefix(strings.TrimSpace(url), "#") {
			continue
		} else if strings.Index(strings.TrimSpace(url), "http:") > 0 {
			urls = append(urls, convertURLToEntity(subStr(strings.TrimSpace(url), "http:"), index, configEntity))
		} else if strings.Index(strings.TrimSpace(url), "https") > 0 {
			urls = append(urls, convertURLToEntity(subStr(strings.TrimSpace(url), "http:"), index, configEntity))
		} else if IsNotEmpty(strings.TrimSpace(url)) {
			urls = append(urls, convertURLToEntity(strings.TrimSpace(url), index, configEntity))
		}
	}
	return urls
}

func convertURLToEntity(url string, index int, configEntity entity.DownloadEntity) entity.URLEntity {
	indexStr := fmt.Sprintf("%d", index)
	title := formatTitle(indexStr, index, 8, configEntity)
	return entity.URLEntity{URL: url, Title: title}
}

func subStr(url string, sp string) string {
	index := strings.LastIndex(url, sp)
	if index > 0 {
		length := len(url)
		return url[index:length]
	}
	return url
}

func createResponse(url string, responseEntity entity.ResponseEntity) (*http.Response, bool) {

	client := &http.Client{Timeout: Default_Sleep_value}
	req, err := http.NewRequest("GET", strings.TrimSpace(url), nil)

	if len(responseEntity.Heads) > 0 {
		for key := range responseEntity.Heads {
			req.Header.Add(key, responseEntity.Heads[key])
		}
	}

	if len(responseEntity.Cokies) > 0 {
		builder := strings.Builder{}
		for _, cookie := range responseEntity.Cokies {
			builder.WriteString(cookie.Name + "=" + cookie.Value + ";")
		}
		req.Header.Add("Cookie", builder.String())
	}

	if nil != err {
		log.Println(url, "---request---", err)
		return nil, false
	}
	resp, error := client.Do(req)
	if nil != error {
		log.Println(url, "---client.Do---", err)
		return nil, false
	}

	return resp, true
}

func ZipOf7Z(titile string, tsPath string, config entity.DownloadEntity) (bool, string) {
	filePath := config.FileDirPath + "/" + titile + ".zip" + config.AudioType
	log.Println("filePath:", filePath)
	cmd := exec.Command(strings.TrimSpace(config.Path7Z), "a", filePath, "-twim", tsPath)
	defer func() { cmdExit(cmd) }()
	err := cmd.Run()

	if nil != err {
		log.Println(filePath, "[", tsPath, "] 7z合成错误:", err)
		return false, filePath
	}
	return true, filePath
}

func ZipOf7Z1(titile string, tsPath string, filePath string, config entity.DownloadEntity) (bool, string) {
	filePath = filePath + ".zip" + config.AudioType
	log.Println("filePath:", filePath, tsPath)
	cmd := exec.Command(strings.TrimSpace(config.Path7Z), "a", filePath, "-twim", tsPath)
	defer func() { cmdExit(cmd) }()
	err := cmd.Run()

	if nil != err {
		log.Println(filePath, "[", tsPath, "] 7z合成错误:", err)
		return false, filePath
	}
	log.Println(strings.TrimSpace(config.Path7Z), "a", filePath, "-twim", tsPath)
	return true, filePath
}
